package schedule

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"github.com/jinzhu/copier"
	"github.com/robfig/cron/v3"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/redis"
	"mall/app/coupon/cmd/rpc/pb"
	productPb "mall/app/product/cmd/rpc/pb"
	"mall/app/seckill/cmd/api/global_key"
	"mall/app/seckill/cmd/api/internal/svc"
	"mall/app/seckill/cmd/api/internal/types"
	"strconv"
	"strings"
	"time"
)

/* UploadSeckillSkuLatest3Day
秒杀商品的定时上架
	每天晚上3点，上架最近三天需要秒杀的商品
* * * * *
*/
func UploadSeckillSkuLatest3Day(svcCtx *svc.ServiceContext) {
	c := cron.New()
	c.AddFunc("0 3 * * ?", func() {
		redisLock := redis.NewRedisLock(svcCtx.RedisClient, global_key.UploadLock)
		redisLock.SetExpire(5)
		if ok, err := redisLock.Acquire(); ok && err == nil {
			uploadSeckillSkuLatest3DayService(svcCtx)
		}
		defer redisLock.Release()
	})
	c.Start()
	select {}
}

func uploadSeckillSkuLatest3DayService(svcCtx *svc.ServiceContext) {
	// 获取需要参加秒杀的活动
	resp, err := svcCtx.CouponRpcClient.GetLatest3DaySession(context.Background(), &pb.GetLatest3DaySessionReq{})
	if err != nil {
		logx.Error(err)
		return
	}
	for _, session := range resp.List {
		logx.Info(session)
	}
	err = saveSessionInfos(svcCtx, resp)
	if err != nil {
		logx.Error(err)
		return
	}
	err = saveSessionsSkuInfos(svcCtx, resp)
	if err != nil {
		logx.Error(err)
		return
	}

}

func saveSessionInfos(svcCtx *svc.ServiceContext, resp *pb.GetLatest3DaySessionResp) error {
	for _, session := range resp.List {
		start, _ := time.ParseInLocation("2006-01-02 15:04:05", session.StartTime, time.Local)
		end, _ := time.ParseInLocation("2006-01-02 15:04:05", session.EndTime, time.Local)
		key := fmt.Sprintf("%s%d_%d", global_key.SessionsCachePrefix, start.Unix(), end.Unix())
		var list []string
		for _, skuInfo := range session.List {
			value := fmt.Sprintf("%d_%d", skuInfo.PromotionSessionId, skuInfo.SkuId)
			list = append(list, value)
		}
		if len(list) > 0 {
			if exists, err := svcCtx.RedisClient.Exists(key); !exists && err == nil {
				_, err := svcCtx.RedisClient.Lpush(key, list)
				if err != nil {
					logx.Error(err)
					return err
				}
			}
		}
	}
	return nil
}

func saveSessionsSkuInfos(svcCtx *svc.ServiceContext, resp *pb.GetLatest3DaySessionResp) error {

	for _, session := range resp.List {
		start, _ := time.ParseInLocation("2006-01-02 15:04:05", session.StartTime, time.Local)
		end, _ := time.ParseInLocation("2006-01-02 15:04:05", session.EndTime, time.Local)
		for _, skuInfo := range session.List {
			field := fmt.Sprintf("%d_%d", skuInfo.PromotionSessionId, skuInfo.SkuId)

			if exists, err := svcCtx.RedisClient.Hexists(global_key.SkukillCacheKey, field); !exists && err == nil {
				var to types.SeckillSkuRedisTo
				_ = copier.Copy(&to, skuInfo)
				result, err := svcCtx.ProductRpcClient.GetProductInfo(context.Background(), &productPb.GetProductInfoReq{SkuId: skuInfo.SkuId})
				if err != nil {
					return err
				}
				_ = copier.Copy(&to.SkuInfo, &result)
				to.StartTime = start.Unix()
				to.EndTime = end.Unix()
				uid, _ := uuid.NewUUID()

				to.RandomCode = strings.ReplaceAll(uid.String(), "-", "")
				bytes, _ := json.Marshal(to)
				err = svcCtx.RedisClient.Hset(global_key.SkukillCacheKey, field, string(bytes))
				if err != nil {
					return err
				}

				key := global_key.Sku_Stock + to.RandomCode
				value := strconv.Itoa(int(skuInfo.SeckillCount))
				err = svcCtx.RedisClient.Set(key, value)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
